#include "Alice/Systems/AABBSys.h"
#include "Alice/Core/World.h"
#include "Alice/Components/AABBComp.hpp"
#include "Alice/Components/TransformComp.hpp"
#include "glm/glm.hpp"

namespace Alice
{

void AABBSys::OnUpdate()
{
    // 线性碰撞检测
    for (auto entity : entitys)
    {
        TransformComp& a_tf_comp = world->GetComp<TransformComp>(entity);
        AABBComp& a_comp = world->GetComp<AABBComp>(entity);

        for (auto other_entity : entitys)
        {
            if (other_entity == entity)
                continue;

            TransformComp& b_tf_comp = world->GetComp<TransformComp>(other_entity);
            AABBComp& b_comp = world->GetComp<AABBComp>(other_entity);
            
            if (IsCollision(a_comp, b_comp, a_tf_comp, b_tf_comp))
            {
                // 两个矩形的中心的差矢量
                glm::vec2 a_center(
                    a_tf_comp.position.x + (a_comp.width / 2),
                    a_tf_comp.position.y + (a_comp.height / 2)
                );
                glm::vec2 b_center(
                    b_tf_comp.position.x + (b_comp.width / 2),
                    b_tf_comp.position.y + (b_comp.height / 2)
                );
                glm::vec2 difference = a_center - b_center;

                // 计算碰撞方向
                Direction collision_dir = CalCollisionDerection(difference);

                // 使用 b 矩形的半长限制 difference 求出 b 边上的矢量（求映射）
                glm::vec2 b_half(b_comp.width / 2, b_comp.height / 2);
                glm::vec2 clamped = glm::clamp(difference, -b_half, b_half);
                // 根据映射求出 a 与 b 的最近点
                glm::vec2 closest = b_center + clamped;
                // 求出 a 的中点到最近点的矢量
                difference = closest - a_center;

                // 计算穿透距离
                float penetration;
                if (collision_dir == Direction::UP ||
                    collision_dir == Direction::DOWN)
                {
                    penetration = (a_comp.height / 2) - std::abs(difference.y);
                }
                else
                {
                    penetration = (a_comp.width / 2) - std::abs(difference.x);
                }

                // 使用实体 ID 作为事件 ID 发送一个事件
                Event collision_event(COLLISION(entity));
                collision_event.SetParam<Entity>("self", entity);
                collision_event.SetParam<Entity>("other", other_entity);
                collision_event.SetParam<Direction>("direction", collision_dir);
                collision_event.SetParam<float>("penetration", penetration);
                world->GetEventMngr()->SendEvent(collision_event);
            }
        }
    }
}

bool AABBSys::IsCollision(AABBComp& a, AABBComp& b, TransformComp& a_tf, TransformComp& b_tf)
{
    bool x_overlaps = (a_tf.position.x < b_tf.position.x + b.width) && (a_tf.position.x + a.width > b_tf.position.x);
    bool y_overlaps = (a_tf.position.y < b_tf.position.y + b.height) && (a_tf.position.y + a.height > b_tf.position.y);

    return x_overlaps && y_overlaps;
}

Direction AABBSys::CalCollisionDerection(glm::vec2& difference)
{
    // 向量顺序与 Direction 枚举顺序对应
    glm::vec2 compass[] = {
        glm::vec2(0.0f, 1.0f),  // 上
        glm::vec2(0.0f, -1.0f), // 下
        glm::vec2(-1.0f, 0.0f), // 左
        glm::vec2(1.0f, 0.0f)   // 右
    };
    
    float max = 0.0f;
    int best_match = -1;

    for (int i = 0; i < 4; i++)
    {
        float dot_product = glm::dot(glm::normalize(difference), compass[i]);
        if (dot_product > max)
        {
            max = dot_product;
            best_match = i;
        }
    }

    return (Direction)best_match;
}

} // namesapce Alice
